import { _decorator, Component, director, Enum, Node, Prefab, quat, Quat, v3, Vec3 } from 'cc';
import { VectorUtil } from './AshFramework/Utils/VectorUtil';
import { TrajectoryPredictor } from './AshFramework/Utils/TrajectoryPredictor';
import { EDITOR } from 'cc/env';
import { ProjectileMath } from './AshFramework/Utils/ProjectileMath';
import { PoolManager } from './AshFramework/Managers/PoolManager';
import { ItemController } from './ItemController';
import { GameController } from './GameController';
import { EnemyController } from './EnemyController';
import { DataManager } from './AshFramework/Managers/DataManager';
import { ZTool } from './AshFramework/Utils/ZTool';
import { CharacterState } from './PlayerController';
import { GameManager } from './GameManager';
import { AudioManager, Audios } from './AshFramework/Managers/AudioManager';
const { ccclass, property } = _decorator;


@ccclass('EnemyAimController')
export class EnemyAimController extends Component {

    @property({ type: Node, displayName: '偏航轴节点', group: { name: '自身节点引用', id: '1' } })
    protected yawAxis: Node = null;

    @property({ type: Node, displayName: '俯仰轴节点', group: { name: '自身节点引用', id: '1' } })
    protected pitchAxis: Node = null;

    @property({ type: Node, displayName: '炮弹发射点节点', group: { name: '自身节点引用', id: '1' } })
    protected firePoint: Node = null;

    @property({ type: TrajectoryPredictor, displayName: '弹道绘制器', group: { name: '弹道', id: '4' } })
    public trajectoryDrawer: TrajectoryPredictor = null;

    @property
    protected _showTrajectory: boolean = true;
    @property({ displayName: '绘制弹道', visible() { return (this.trajectoryDrawer != null); }, group: { name: '弹道', id: '4' } })
    public get showTrajectory() {
        return this._showTrajectory;
    }
    public set showTrajectory(value) {
        this._showTrajectory = value;
        if (!EDITOR && this.trajectoryDrawer) {
            if (value) {
                this.curTargetPos && this.aim(this.curTargetPos);
            } else {
                this.trajectoryDrawer.clear();
            }
        }
    }

    enemyCtrl: EnemyController;

    protected velocity: number = 0;

    /*** 俯仰角*/
    public get pitch() { return this.pitchAxis.eulerAngles.x; }
    protected set pitch(value: number) {
        this.pitchAxis.setRotationFromEuler(value, 0, 0);
    }

    /*** 偏航角*/
    public get yaw() { return this.yawAxis.eulerAngles.y; }
    protected set yaw(value: number) {
        this.yawAxis.setRotationFromEuler(0, value, 0);
    }

    /*** 大炮的世界坐标*/
    protected get mainPosition() { return this.yawAxis.getWorldPosition(); }

    /*** 大炮的正前方向向量（+z）*/
    protected get mainForward() { return this.yawAxis.parent.forward.negative(); }

    /*** 大炮的正上方向向量（+y）*/
    protected get mainUp() { return this.yawAxis.up; }

    /*** 当前瞄准的目标位置*/
    protected curTargetPos: Vec3 = new Vec3(0, -2, 2);

    protected onLoad(): void {
        this.enemyCtrl = this.node.getComponent(EnemyController)
    }

    public aim(targetPos: Vec3) {
        // 保存另作他用
        this.curTargetPos.set(targetPos);

        // 偏航角（Yaw）
        // 大炮直接看向目标点的方向矢量
        const direction = Vec3.subtract(new Vec3, targetPos, this.mainPosition);
        // 计算方向矢量和大炮的向前矢量之间的夹角（有符号）
        const yawAngle = -VectorUtil.signedAngle(direction, this.mainForward, this.mainUp);

        // 俯仰角（Pitch）和速度
        let pitchAngle = NaN,
            velocity = NaN;
        let fixedTrajectoryDistance = false;

        const result = this.calculateWithMaxHeight(targetPos);
        pitchAngle = -result.angle;
        velocity = result.velocity * 1.3;

        // 角度值是否有效
        if (isNaN(pitchAngle)) {
            pitchAngle = this.pitch;    // 维持当前角度
        }

        // 旋转
        this.rotateTo(pitchAngle, yawAngle);

        // 记录速度
        if (!isNaN(velocity)) {
            this.velocity = velocity;
        }

        // 绘制弹道
        if (this.showTrajectory && this.trajectoryDrawer) {
            this.drawTrajectory(targetPos, -this.pitch, this.velocity, fixedTrajectoryDistance);
        }
    }

    /**
     * 绘制弹道
     * @param targetPos 目标位置
     * @param angle 初始角度
     * @param velocity 初始速度
     * @param fixedDistance 固定距离
     */
    protected drawTrajectory(targetPos: Vec3, angle: number, velocity: number, fixedDistance: boolean) {
        const firePos = this.firePoint.getWorldPosition();
        if (fixedDistance) {
            const distance = ProjectileMath.calculateDisplacementAtMoment(angle, velocity, 2).x;
            this.trajectoryDrawer.draw(firePos, targetPos, angle, velocity, distance);
        } else {
            this.trajectoryDrawer.draw(firePos, targetPos, angle, velocity);
        }
    }

    /**
     * 旋转至指定角度
     * @param pitch 俯仰角
     * @param yaw 偏航角
     */
    public rotateTo(pitch: number, yaw: number) {
        this.pitch = pitch;
        this.yaw = yaw;
    }

    /**
     * 根据速度计算角度
     * @param targetPos 目标位置
     * @param velocity 初始角度
     */
    protected calculateAngle(targetPos: Vec3, velocity: number) {
        const { horizontal, vertical } = this.calculateDisplacement(targetPos);
        return ProjectileMath.calculateWithVelocity(horizontal, vertical, velocity);
    }

    /**
     * 根据角度计算速度
     * @param targetPos 目标位置
     * @param angle 初始角度
     */
    protected calculateVelocity(targetPos: Vec3, angle: number) {
        const { horizontal, vertical } = this.calculateDisplacement(targetPos);
        return ProjectileMath.calculateWithAngle(horizontal, vertical, angle);
    }

    /*** 根据最大高度计算速度和角度*/
    protected calculateWithMaxHeight(targetPos: Vec3) {
        const { horizontal, vertical } = this.calculateDisplacement(targetPos);
        const maxHeight = Math.max(0.5, vertical + (horizontal * 0.3));  // 最大高度
        return ProjectileMath.calculateWithMaxHeight(horizontal, vertical, maxHeight);
    }

    /*** 计算位移距离 @param targetPos 目标位置*/
    protected calculateDisplacement(targetPos: Vec3) {
        // 从目标点到发射点的方向矢量
        const firePos = this.firePoint.getWorldPosition(),
            direction = Vec3.subtract(new Vec3, targetPos, firePos);
        // 垂直位移（相当于 targetPos.y - firePos.y）
        const vertical = direction.y;
        // 水平位移（将方向矢量投影到水平面上，其长度就是水平位移的长度）
        const horizontal = VectorUtil.projectOnPlane(direction, Vec3.UP).length();
        return { horizontal, vertical };
    }

    public fire(targetPos?: Vec3) {
        targetPos && this.aim(targetPos);// 瞄准

        this.scheduleOnce(() => {
            AudioManager.PlaySound(Audios.Throw);
            this.trajectoryDrawer.clear();
            this.enemyCtrl.PlayAni(CharacterState.Throw);
            this.shoot(this.velocity);// 发射
        }, ZTool.GetRandom(0.5, 1));
    }

    shoot(velocity: number) {
        this.enemyCtrl.DestroyItem();

        PoolManager.GetNode("Prefabs/ItemController", director.getScene()).then((node: Node) => {
            const itemCtrl = node.getComponent(ItemController);

            itemCtrl.Init(this.enemyCtrl.itemIndex, itemCtrl.damage);

            node.setWorldPosition(this.firePoint.getWorldPosition());
            node.setWorldRotation(this.firePoint.getWorldRotation());

            // itemCtrl.node.setWorldPosition(this.firePoint.getWorldPosition());
            // itemCtrl.node.setRotationFromEuler(v3(node.eulerAngles.x, node.eulerAngles.y, node.eulerAngles.z + 90));

            const direction = node.forward.negative();

            direction.multiplyScalar(velocity);

            itemCtrl.rigidBody.setLinearVelocity(direction);

            itemCtrl.DelayDestroy();

            this.scheduleOnce(() => {
                GameController.Instance.IsRoundPlayer = true;
            }, 3);
        });
    }

}